* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background: #66c7f4;
}

@ballSize: 30px; //  小球尺寸
@containerSize: 450px; // 容器尺寸
@n: 36; // 小球数量
@pdeg: 360deg / @n; // 旋转角度
@ani-duration: 2000ms; // 动画持续时间

.loading {
    width: @containerSize;
    height: @containerSize;
    margin: 100px auto;
    position: relative;
    border-radius: 50%;

    .dot {
        position: absolute;
        left: 50%;
        top: 50%;
        width: @ballSize;
        height: @ballSize;
        margin-left: calc(-@ballSize / 2);
        margin-top: calc(-@ballSize / 2);
        perspective: 70px;
        transform-style: preserve-3d;

        &::before,
        &::after {
            content: '';
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
        }

        &::before {
            background: #000;
            top: -100%;
            animation: moveBlack @ani-duration infinite;
        }

        &::after {
            background: #fff;
            top: 100%;
            animation: moveWhite @ani-duration infinite;
        }
    }
}

@keyframes moveWhite {
    0% {
        animation-timing-function: ease-in;
    }

    25% {
        transform: translate3d(0, -100%, -@ballSize);
        animation-timing-function: ease-out;
    }

    50% {
        transform: translate3d(0, -200%, 0);
        animation-timing-function: ease-in;
    }

    75% {
        transform: translate3d(0, -100%, @ballSize);
        animation-timing-function: ease-out;
    }
}

@keyframes moveBlack {
    0% {
        animation-timing-function: ease-in;
    }

    25% {
        transform: translate3d(0, 100%, @ballSize);
        animation-timing-function: ease-out;
    }

    50% {
        transform: translate3d(0, 200%, 0);
        animation-timing-function: ease-in;
    }

    75% {
        transform: translate3d(0, 100%, -@ballSize);
        animation-timing-function: ease-out;
    }
}

.loop(@i) when(@i <= @n) {
    .dot:nth-child(@{i}) {
        transform: rotate(calc(@pdeg * @i)) translateY(calc(-@containerSize / 2));

        &::before,
        &::after {
            animation-delay: calc(-@ani-duration * 6 / @n * @i);
        }
    }

    .loop(@i + 1);
}

.loop(1);